#include "lt_hashmap.h"

unsigned int xmap_hash(char *str)
{
    register unsigned int h;
    register unsigned char *p;

    for(h=0, p = (unsigned char *)str; *p ; p++) {
        h = 31 * h + *p;
    }

    return h;
}

/**
 * @description: 创建一个node数量为n的hash表
 * @param {n}    node数量
 * @return {*}   创建的hash map
 */
HashMap* xmap_init(int n)
{
    HashMap* hashMap = (HashMap*)calloc(1, sizeof(HashMap));
    hashMap->hashArr = (HashNode**)calloc(n, sizeof(HashNode*));
    if (hashMap==NULL || hashMap->hashArr==NULL) {
        return NULL;
    }
    hashMap->size = n;
    return hashMap;
}

static char *my_strdup(char* s, unsigned long int len)
{
    void *new = malloc(len);
       if (new == NULL)
          return NULL;
    return (char *)memcpy(new,s,len);
}

/**
 * @description:     插入1个键值对
 * @param {*hashMap} 待操作的hash表
 * @param {*key}     键
 * @param {*value}   值
 * @return {int}     是否操作成功，0:失败；1:成功
 * @attention 如果key相同，则后插入的value会覆盖已有的value
 */
int xmap_put(HashMap* hashMap, char* key, char* value, unsigned long int len)
{
    // 创建一个node节点
    HashNode* node = (HashNode*)calloc(1, sizeof(HashNode));
    if (node == NULL) {
        return 0;
    }

    // 复制键和值
    node->key = strdup(key);
    node->value = my_strdup(value, len);
    node->next = NULL;
    // 对hash结果求余，获取key位置
    int index = xmap_hash(key) % hashMap->size;
    // 如果当前位置没有node，就将创建的node加入
    if (hashMap->hashArr[index] == NULL) {
        hashMap->hashArr[index] = node;
    }
    // 否则就要在已有的node往后添加
    else {
        // 用于遍历node的临时游标
        HashNode *temp = hashMap->hashArr[index];
        // 记录上一个node
        HashNode *prev = temp;
        // 循环遍历至最后一个节点node_end的next
        while (temp != NULL) {
            // 如果两个key相同，则直接用新node的value覆盖旧的
            if (strcmp(temp->key, node->key) == 0) {
                // 释放旧value
                free(temp->value);
                // 复制新value
                temp->value = strdup(node->value);
                return 1;
            }
            prev = temp;
            temp = temp->next;
        }
        // 最后一个节点node_end的next指向新建的node
        prev->next = node;
    }
    return 1;
}

/**
 * @description:     通过key查找value
 * @param {*hashMap} 待操作的hash表
 * @param {*key}     通过key找对应的value
 * @return {*}       找到的value
 */
char* xmap_get(HashMap* hashMap, char* key)
{
    // 对hash结果求余，获取key位置
    int index = xmap_hash(key) % hashMap->size;
    // 用于遍历node的临时游标
    HashNode *temp = hashMap->hashArr[index];
    // 循环遍历至最后一个节点node_end的next
    while (temp != NULL) {
        // 如果两个key相同，则用新node的value覆盖旧的
        if (strcmp(temp->key, key) == 0) {
            return temp->value;
        }
        temp = temp->next;
    }
    return NULL;
}

/**
 * @description:     释放hash map内存
 * @param {*hashMap} 待操作的hash表
 * @return {}
 */
void xmap_fint(HashMap* hashMap)
{
    for (int i = 0; i < hashMap->size; i++)
    {
        // 用于遍历node的临时游标
        HashNode *temp = hashMap->hashArr[i];
        HashNode *prev = temp;
        // 循环遍历至最后一个节点node_end的next
        while (temp != NULL) {
            prev = temp;
            temp = temp->next;
            free(prev->key);
            free(prev->value);
            free(prev);
        }
    }
    free(hashMap->hashArr);
    free(hashMap);
    hashMap->hashArr = NULL;
    hashMap = NULL;
}

/**
 * @brief 删除由key指定的键值对
 * @param hashMap 待操作的hash表
 * @param key
 * @return
 */
int xmap_del(HashMap* hashMap, char* key)
{
    // 对hash结果求余，获取key位置
    int index = xmap_hash(key) % hashMap->size;
    // 用于遍历node的临时游标
    HashNode *temp = hashMap->hashArr[index];
    if (temp == NULL) {
        return 0;
    }

    // 如果第一个就匹配中
    if (strcmp(temp->key, key) == 0) {
        // printf("找到:%s->%s\n", temp->key, temp->value);
        hashMap->hashArr[index] = temp->next;
        free(temp->key);
        free(temp->value);
        free(temp);
        return 1;
    }else {
        HashNode *prev = temp;
        temp = temp->next;
        // 循环遍历至最后一个节点node_end的next
        while (temp != NULL) {
            // 如果两个key相同，则用新node的value覆盖旧的
            if (strcmp(temp->key, key) == 0) {
                // printf("找到:%s->%s\n", temp->key, temp->value);
                prev->next = temp->next;
                free(temp->key);
                free(temp->value);
                free(temp);
                return 1;
            }
            prev = temp;
            temp = temp->next;
        }
    }
    return 0;
}

/**
 * @description: 打印hash map
 * @param {*hashMap}
 * @return {}
 */
void xmap_print(HashMap* hashMap)
{
    printf("===========PrintHashMap==========\n");
    HashNode* node = NULL;
    for (int i = 0; i < hashMap->size; i++)
    {
        node = hashMap->hashArr[i];
        if (node != NULL) {
            HashNode* temp = node;
            while (temp != NULL) {
                printf("[%d]: %s -> %s\t", i, temp->key, temp->value);
                temp = temp->next;
            }
            printf("\n");
        }
    }
    printf("===============End===============\n");
}

